/**
 * 工具函数：uid生成函数
 * @returns {Function} uid
 */
function createUidFactory(prefix = 'uid') {
    let index = 0;
    return () => {
        index += 1;
        return `${prefix}-${index}`;
    };
}

/**
 * 生成前缀为vvfefe-upload的uid
 */
export const genFileUid = createUidFactory('vv-fefe-upload-file-uid');
export const genAppUid = createUidFactory('vv-fefe-upload-app-uid');

/**
 * 这是一个空函数，作为属性或者变量的缺省值用
 */
export function noop() {
    // 空函数
}

/**
 * 获取对象的类型
 * @param {any} obj
 * @return {String}
 * 
 * @example
 * datatype([]) => Array
 * datatype() => Undefined
 * datatype(null) => Null
 * datatype(1) => Number
 */
export function datatype(obj) {
    return Object.prototype.toString.call(obj).replace(/^\[object\s+([a-zA-Z]+)\]$/, '$1');
}

/**
 * 判断对象是否时一个Promise实例
 * @param {any} obj
 * @return {Boolean}
 */
export function isPromise(obj) {
    return (
        !!obj &&
        (
            typeof obj === 'object' ||
            typeof obj === 'function'
        ) &&
        typeof obj.then === 'function'
    );
}

/**
 * 判断对象是否是一个纯净的对象
 * @param  {any}  obj
 * @return {Boolean}
 * @reference https://github.com/jonschlinkert/is-plain-object
 */
export function isPlainObject(obj) {
    if (datatype(obj) !== 'Object') {
        return false;
    }

    const ctor = obj.constructor;

    if (typeof ctor !== 'function') {
        return false;
    }

    const prot = ctor.prototype;

    if (datatype(prot) !== 'Object') {
        return false;
    }

    if (!prot.hasOwnProperty('isPrototypeOf')) {
        return false;
    }

    return true;
}

/**
 * 类Promise的方式执行回调方法
 * @param {Function|Promise} ret 返回执行结果
 * @param {Function} resolve 执行结果返回非false时
 * @param {Function} reject 执行结果返回false的毁掉
 */
// export function likePromiseCall(ret, resolve, reject = noop) {
//     if (isPromise(ret)) {
//         return ret.then(result => {
//             resolve(result);
//             return result;
//         }).catch(e => {
//             reject(e);
//         });
//     }
    
//     return (
//         ret !== false ?
//         resolve(ret) :
//         reject(ret)
//     );
// }

/**
 * transfer size from number to xx K/ XxxM / xxG
 * 
 * @param {Number} size
 * @returns {String} size 
 */
export function sizeCaculator(size) {
    let fileSize = parseFloat(size, 10);
    // fileSize为浮点数 用 < 0.000001 替代 === 0
    if (isNaN(fileSize) || fileSize < 0.0000001) {
        return 0;
    }
    const SIZE_SUFFIX = ['B', 'KB', 'MB', 'GB', 'TB', 'PB'];
    let suffixIndex = 0;

    // 在Mac上实验发现 取1024造成显示的大小和实际大小不一致
    // 因为单位制不同 见 https://superuser.com/questions/938234/size-of-files-in-windows-os-its-kb-or-kb
    const BIT_NUMBER_SYSTEM = 1024;
    while (
        fileSize >= BIT_NUMBER_SYSTEM &&
        suffixIndex < SIZE_SUFFIX.length
    ) {
        suffixIndex++;
        fileSize /= BIT_NUMBER_SYSTEM;
    }

    const suffix = SIZE_SUFFIX[suffixIndex];
    fileSize = fileSize.toFixed(2);

    return `${fileSize}${suffix}`;
}

/**
 * 验证文件类型是否合理
 * @param {File} file 
 * @param {String} accept input[type=file]的属性值，关于accept的值参考：https://developer.mozilla.org/zh-CN/docs/Web/HTML/Element/input/file#attr-accept
 */
export function validateFileType(file, accept) {
    if (file && accept) {
        const acceptedFileTypes = accept.split(',');
        const fileName = file.name || '';
        const mimeType = file.type || '';

        const mimeTypeRe = /\/.*$/;
        const baseMimeType = mimeType.replace(mimeTypeRe, '');

        return acceptedFileTypes.some(type => {
            const validType = type.trim();

            if (validType.charAt(0) === '.') { // for lika a ".jpg"
                const re = new RegExp(`\\${validType}$`, 'i');
                return re.test(fileName);
            } else if (/\/\*$/.test(validType)) { // for like a "image/*"
                return baseMimeType === validType.replace(mimeTypeRe, '');
            }

            return mimeType === validType; // for like a "image/png"
        });
    }
    return true;
}

/**
 * 遍历文件树，应用于拖拽场景
 */
export function traverseFileTree(files, callback, isAccepted) {
    const fileList = Array.prototype.slice.call(files);
    const _traverseFileTree = (item, path = '') => {
        if (item.isFile) {
            item.file(file => {
                if (isAccepted(file)) {
                    if (item.fullPath && !file.webkitRelativePath) {
                        Object.defineProperties(file, {
                            webkitRelativePath: {
                                writable: true
                            }
                        });
                        file.webkitRelativePath = item.fullPath.replace(/^\//, '');
                        Object.defineProperties(file, {
                            webkitRelativePath: {
                                writable: false
                            }
                        });
                    }
                    callback([file]);
                }
            });
        } else if (item.isDirectory) {
            loopFiles(item, entries => {
                entries.forEach(entryItem => {
                    _traverseFileTree(entryItem, `${path}/${item.name}/`);
                });
            });
        }
    };
    fileList.forEach(file => {
        _traverseFileTree(file.webkitGetAsEntry());
    });
}
function loopFiles(item, callback) {
    const dirReader = item.createReader();
    let fileList = [];

    (function sequence() {
        dirReader.readEntries(entries => {
            const entryList = Array.prototype.slice.call(entries);
            fileList = fileList.concat(entryList);

            // 检查是否所有文件可被查看
            const isFinished = !entryList.length;

            if (isFinished) {
                callback(fileList);
            } else {
                sequence();
            }
        });
    })();
}

/**
 * 生成预览效果图
 * 参考链接：https://developer.mozilla.org/en-US/docs/Web/API/FileReader/readAsDataURL
 */
export function previewFile(file) {
    return new Promise((resolve, reject) => {
        try {
            const reader = new FileReader();
            reader.onloadend = () => {
                resolve(reader.result);
            };
            reader.onerror = error => {
                reject(error);
            };
            reader.readAsDataURL(file);
        } catch (error) {
            reject(error);
        }
    });
}

/**
 * base64 转 File 对象
 * 1. dataURL -> Blob
 * 2. Blob -> File
 * 
 * 兼容：ie9+
 * 
 * @param {String} dataURL 
 * @param {String} fileName
 * @returns {Blob}
 */
export function dataURL2File(dataURL, fileName) {
    const arr = dataURL.split(',');
    const mime = arr[0].match(/:(.*?);/)[1];
    const bstr = atob(arr[1]);
    const u8arr = new Uint8Array(bstr.length);

    let n = bstr.length;
    while (n--) {
        u8arr[n] = bstr.charCodeAt(n);
    }
    const blob = new Blob([u8arr], {
        type: mime
    });

    // Blob to File
    // set lastModifiedDate and name
    blob.lastModifiedDate = new Date();
    blob.name = fileName;

    return blob;
};